<?php

/**
 * Manages your dynamic/stored params,generates sql,processes params in url
 *
 * @author Ishtiaque Shahrier <md.ishtiaque@newgenbd.net>
 * @package search
 * @subpackage libraries
 */
class search_processor_l_search {
    const DEFAULT_PER_PAGE = 10;
    /**
     *
     * @var array array of param object
     */
    protected $params = array();
    /**
     *
     * @var string name of the main table.
     */
    protected $main_table;
    /**
     *
     * @var bool 
     */
    protected $in_debug_mode = FALSE;

    /**
     *
     * @param string $main_table
     * @param bool $in_debug_mode sets processor in debug mode
     */
    public function __construct($main_table, $in_debug_mode=FALSE) {
        $this->main_table = $main_table;
        $this->in_debug_mode = $in_debug_mode;
    }

    /**
     * Add a param in the stack for search/sorting...
     * @param a_base_param_l_search $param
     * @return search_processor_l_search returns self for chaining
     */
    public function add_param(a_base_param_l_search $param) {
        if (!array_key_exists($param->get_id(), $this->params)) {
            $this->params[$param->get_id()] = $param;
        } else {
            throw new err_duplicate_param_l_search($param->get_id());
        }
        return $this;
    }

    /**
     * Sets the processor in.not in debug mode.
     * If sets to TRUE then the generated SQL is logged
     *
     * @param bool $flag
     */
    public function toogle_debug($flag) {
        $this->in_debug_mode = $flag;
    }

    /**
     * Traverse the param stack and combines/generates the sql
     * @return string the sql string
     */
    protected function generate_sql($count_only=FALSE) {

        $sql = "SELECT ";
        
        $selects = array();
        $joins   = array();
        $wheres  = array();
        $orders  = array();

        if (count($this->params)) {
            foreach ($this->params as $param) {
                //for counting selecting field is not necessary
                if($count_only===FALSE){
                    if (($line = $param->get_select_line()) !== NULL) {
                        $selects[] = $line;
                    }
                }
                if (($line = $param->get_join_line()) !== NULL) {
                    $joins[] = $line;
                }
                if (($line = $param->get_where_line()) !== NULL) {
                    $wheres[] = $line;
                }
                if (($line = $param->get_order_line()) !== NULL) {
                    $orders[] = $line;
                }
            }
        }
        //for counting selecting field is not necessary..we need to include COUNT(*)
        if ($count_only===FALSE && count($selects)){
            $sql.=implode(", ", $selects);
            $sql .= " FROM $this->main_table ";
        }else{
            $sql .= " count(*) as count FROM $this->main_table ";
        }
        
        if (count($joins)) {
            $sql.= implode(" ", $joins);
        }

        if (count($wheres)) {
            $sql.=" WHERE ";
            $sql.= implode(" AND ", $wheres);
        }
        if (count($orders)) {
            $sql.= " ORDER BY ";
            $sql.= implode(" , ", $orders);
        }

        return $sql;
    }
    /**
     * Returns the total number of result found
     *
     * @return int number of total result
     */
    public function count_result(){
        $sql = $this->generate_sql(TRUE);
        $query = get_instance()->db->query($sql);
        return $query->row()->count;
    }
    /**
     * Executes the generated sql and returns poulated model object array
     *
     * @param a_base_model|stdClass $model_object_to_populate
     * @param int $page
     * @param int $offset
     * @return array array of populated model object using the generated sql
     */
    public function get_result($model_object_to_populate,$offset=0, $per_page=self::DEFAULT_PER_PAGE ) {
        $sql = $this->generate_sql();        
        $sql.=" LIMIT $offset,$per_page";
        if ($this->in_debug_mode) {
            logger::i()->info($sql, "sql", "search");
        }
        // trace($sql);
  
        if (is_a($model_object_to_populate, "a_base_model_datamapper")) {
            return $model_object_to_populate->query($sql);
        } else {
            //@TO_DO : for any other kinda model...
        }
    }

    /**
     * Adds the detected param object from URL in the param stack/array
     * @return array array of params(std data) it ADDED from the URL
     */
    public function add_params_from_url() {
        $srv = new service_l_search();
        $param_objs = $srv->grab_url_params();
        $added_param_objs = array();
        $caught = array();
        if (count($param_objs) > 0) {
            foreach ($param_objs as $obj) {
                if (quick_include("search", $obj->driver)) {
                    try {
                        $param_obj = new $obj->driver($obj);
                        $this->add_param($param_obj);
                        $added_param_objs[$param_obj->get_id()] = $obj;
                    } catch (err_duplicate_param_l_search $e) {
                        logger::i()->error($e->getMessage(), "driver", "search");
                    }
                } else {
                    logger::i()->error("Search driver CLASS not found : $driver ", "driver", "search");
                }
            }
        }
        unset($srv);
        
        return $added_param_objs;
    }

}

?>